
import { renderComponent } from '@/components/apsForm/renderComponent'
import LbRender from '@/components/lb-table/lb-render'
const responsive = {
    1: { xs: 24, sm: 24 },
    2: { xs: 24, sm: 24, md: 12 },
    3: { xs: 24, sm: 12, md: 12, lg: 8 },
    4: { xs: 24, sm: 12, md: 8, lg: 6 }
};
const FormBuilder = {
    name: 'apsForm',
    components: {
        LbRender
    },
    props: {
        model: {
            type: Object,
            default() {
                return {}
            }
        },
        formRef: {
            type: String,
            default() {
                return 'formDefault'
            }
        },
        config: {
            type: Object,
            default() {
                return {
                    formAttr: {},
                    rules: {},
                    properties: {}
                }
            }
        },
        labelWidth: {
            type: String,
            default: '120px'
        }
    },
    watch: {
        values: {
            handler(values) {
                this.$emit('input', values);
                this.$forceUpdate()
            },
            deep: true,
            immediate: true
        },
        model: {
            handler() {
                if (!this.updating) {
                    this.values = this.mergeValues()
                } else {
                    this.updating = false
                }
            },
            immediate: true,
            deep: true
        }
    },
    data() {
        return {
            updating: false,
            values: this.mergeValues(),
        }
    },
    render(h) {
        const $this = this
        const bsColumn = $this.config?.formAttr?.bsColumn || undefined
        const formSoltButton = Object.prototype.toString.call($this.config?.formSoltButton || undefined) === '[object Array]' ? $this.config?.formSoltButton : undefined
        const title = $this.config?.title
        const describe = $this.config?.describe
        if (bsColumn) {
            return [h('el-form', {
                props: {
                    ...$this.config.formAttr,
                    model: $this.values,
                    labelWidth: $this.labelWidth,
                },
                ref: $this.formRef
            },
                [
                    (title ? (h('h3', {
                        class: 'aps-title'
                    }, title)) : []),
                    (describe ? h('p', {
                        class: 'aps-describe'
                    }, describe) : []),
                    ...($this.$slots.prepend || []),
                    [h('el-row', {
                        attrs: {
                            ...(bsColumn?.custom || {})
                        }
                    },
                        [...($this.renderFormItems(h) || []),
                        ...($this.$slots.append || [])]
                    )],
                    formSoltButton ? ($this.renderFormSlotButtons(h)) : []
                ]
            )]
        } else {
            return [h(
                'el-form', {
                props: {
                    ...$this.config.formAttr,
                    model: $this.values,
                    labelWidth: $this.labelWidth
                },
                ref: $this.formRef
            },
                [
                    (title ? (h('h3', {
                        class: 'aps-title'
                    }, title)) : []),
                    (describe ? h('p', {
                        class: 'aps-describe'
                    }, describe) : []),
                    ...($this.$slots.prepend || []),
                    ...($this.renderFormItems(h) || []),
                    ...($this.$slots.append || []),
                    formSoltButton ? ($this.renderFormSlotButtons(h)) : []
                ]
            )]
        }
    },
    created() {
        this.$emit('input', this.values)
    },
    mounted() {
    },
    methods: {
        resetFields() {
            const $this = this;
            $this.$refs[$this.formRef].resetFields();
        },
        setLoadingBtnVal(key, value) {
            this.loadingBtn.map((item, i) => {
                if (item.key === key) {
                    this.loadingBtn[i].value = value
                }
            })
        },
        setFieldValue(key, value) {
            const $this = this;
            $this.values[key] = value
        },
        setFieldsValue(obj) {
            const $this = this;
            Object.keys(obj).map(key => {
                $this.values[key] = obj[key]
            })
        },
        getLoadingBtnVal(key) {
            let loadingStatus = false
            this.loadingBtn.map((item, i) => {
                if (item.key === key) {
                    loadingStatus = this.loadingBtn[i].value
                }
            })
            return loadingStatus
        },
        getFieldsValue() {
            const $this = this;
            return $this.values
        },
        validate(cb) {
            const $this = this;
            $this.$refs[$this.formRef].validate(cb);
        },
        validateField(cb) {
            $this.$refs[$this.formRef].validateField(cb);
        },
        validateFields(cb) {
            const $this = this;
            return new Promise((resolve, reject) => {
                $this.$refs[$this.formRef].validate((valid, err) => {
                    if (valid) resolve($this.values)
                    else reject(err)
                })
            })
        },
        mergeValues() {
            const $this = this;
            const { model } = $this;
            const { properties } = $this.config;
            let formData = {}
            Object.keys(properties).map(key => {
                const { typeName, multiple } = properties[key]
                let defaultValue
                if (typeName === 'checkbox' || (typeName === 'select' && multiple)) {
                    defaultValue = defaultValue != null ? properties[key].defaultValue : []
                } else {
                    defaultValue = properties[key].defaultValue
                }
                Object.assign(formData, {
                    [key]: defaultValue
                })
            })
            let mergeValues = {
                ...formData,
                ...model
            }
            Object.keys(formData).forEach(key => {
                if (Array.isArray(formData[key]) && formData[key].length === 0 && (!model || !model[key])) {
                    mergeValues[key] = []
                }
                const { typeName } = properties[key]
                if (typeName?.includes('button')) delete mergeValues[key]
            })
            return mergeValues
        },
        filterAttrs(item = {}) {
            const keys = Object.keys(item)
            const attrs = {}
            keys.forEach(key => {
                const value = item[key]
                if (
                    typeof value === 'number' ||
                    typeof value === 'string' ||
                    typeof value === 'boolean'
                ) {
                    attrs[key] = value
                }
            })
            if (attrs?.typeName) {
                delete attrs.typeName
            }
            return attrs
        },
        filterEvents(item = {}) {
            const keys = Object.keys(item)
            const events = {}
            keys.forEach(key => {
                const value = item[key]
                if (typeof value === 'function') {
                    events[key] = value
                }
            })
            return events
        },
        renderFormItems(h) {
            const $this = this
            const { properties, formAttr } = $this.config;
            const { bsColumn } = formAttr
            return Object.keys(properties).map(key => {
                const { display, render, label, size } = properties[key]
                const col = bsColumn?.col || 0;
                const newCol = (col > 4) ? 4 : col
                const custom = bsColumn?.custom || undefined
                const customResponsive = custom || responsive
                const middle = bsColumn?.middle || undefined
                if (display) {
                    return h('')
                } else if (render) {
                    const rcol = properties[key]?.bsColumn?.col ?? newCol;
                    const rbsColumn=properties[key]?.bsColumn || bsColumn;
                    if (rcol) {
                        return h('el-col', {
                            attrs: {
                                ...rbsColumn?.custom || '',
                                ...customResponsive[rcol]
                            },
                        }, [(h('el-form-item',
                            {
                                class: 'aps-form-item' + (middle ? '-middle' : ''),
                                props: {
                                    prop: key,
                                    label,
                                    size
                                }
                            }, [
                            h('lb-render', {
                                props: {
                                    render
                                }
                            })]))])
                    } else {
                        return (h('el-form-item',
                            {
                                class: 'aps-form-item' + (middle ? '-middle' : ''),
                                props: {
                                    prop: key,
                                    label,
                                    size
                                }
                            }, [
                            h('lb-render', {
                                props: {
                                    render
                                }
                            })]))
                    }
                } else {
                    return $this.renderFormItem(h, properties[key], key, col > 4 ? 4 : col, formAttr);
                }
            })
        },
        renderFormItem(h, item, key, col, formAttr) {
            const $this = this
            return renderComponent(h, item, key, $this, col, formAttr, responsive)
        },
        renderFormSlotButtons(h) {
            const $this = this
            const { formSoltButton } = $this.config;
            const middle = $this.config?.formAttr?.bsColumn?.middle
            return h('el-form-item', {
                class: middle ? 'aps-middle-footer' : 'aps-footer'
            }, formSoltButton.map((item) => {
                if(item.display){
                    return ('')
                }else{
                    return $this.renderFormSlotButton(h, item, $this)
                }
            }))
        },
        renderFormSlotButton(h, item, that) {
            const $this = this
            const modelEvents = {
                ...$this.filterEvents(item)
            }
            return [h('el-button', {
                style: item.style || {},
                attrs: {
                    ...$this.filterAttrs(item)
                },
                on: {
                    ...modelEvents
                }
            }, item?.label ?? '')]
        },
    }
}
export default FormBuilder